-
Notifications
You must be signed in to change notification settings - Fork 55
Neighboring pixel suppression for better multi-touch gestures #205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Neighboring pixel suppression for better multi-touch gestures #205
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a neighboring pixel suppression feature to improve multi-touch gesture support on devices where fingers are positioned close together, particularly targeting the Surface Laptop Studio 2 touchpad. The implementation finds local maxima in the heatmap and darkens surrounding pixels to prevent cluster spanning from incorrectly merging nearby touch contacts, while preserving accurate maxima positions and intensity values for Gaussian fitting.
Key changes:
- Adds a new suppression algorithm that darkens pixels around detected maxima within a configurable radius by a configurable factor
- Implements dual-image approach: original blurred image for maxima detection and Gaussian fitting, suppressed image for cluster spanning
- Adds configuration options
PeakSuppressionRadiusandPeakSuppressionFactorto control the suppression behavior
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/contacts/detection/algorithms/suppression.hpp | New algorithm implementing neighbor pixel suppression with euclidean radius-based darkening and maxima preservation |
| src/contacts/detection/detector.hpp | Integrates suppression into detection pipeline by adding suppressed image buffer and conditional application during cluster spanning |
| src/contacts/detection/config.hpp | Adds configuration fields for suppression radius and factor with documentation |
| src/core/generic/config.hpp | Declares suppression config fields and passes them to detection config |
| src/core/linux/config-loader.hpp | Loads suppression parameters from configuration files |
| etc/iptsd.conf | Documents the new PeakSuppressionRadius and PeakSuppressionFactor configuration options |
| etc/presets/surface-laptop-studio-2.conf | Provides device-specific configuration for Surface Laptop Studio 2 with suppression enabled |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /* | ||
| * Darken pixels around each maxima by a constant factor, while leaving maxima pixels unchanged. | ||
| * | ||
| * This is intended to "sharpen" peaks / deepen valleys between peaks so that cluster spanning | ||
| * is less likely to connect neighboring contacts. | ||
| * | ||
| * Behavior: | ||
| * - out is initialized as a copy of in | ||
| * - for each maxima, all pixels within euclidean radius (excluding the center pixel) are reduced: | ||
| * out(y,x) = min(out(y,x), in(y,x) * factor) | ||
| * - maxima pixels are restored to their original values (exactly unchanged) | ||
| * | ||
| * Notes: | ||
| * - If neighborhoods overlap, the result is still "at most factor" darkening (no stacking), | ||
| * because we always compare against (in * factor), not (out * factor). | ||
| */ |
Copilot
AI
Dec 29, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function documentation uses a C-style comment (/) instead of the Doxygen-style comment (/!) that is consistently used throughout the codebase for documenting functions. For consistency with other algorithm files like maximas.hpp, cluster.hpp, neutral.hpp, and ellipse.hpp, this should use the Doxygen comment style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot propose a commit/change to fix that.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
qzed
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a good idea, thanks!
I was having issues with the Surface Laptop Studio 2 touch pad, where multi-touch gestures were nearly impossible to make work when your fingers are close together. I came up with the idea that one could find local maxima locations, and dim the neighboring pixels resulting in a more reliable way to use multi-touch gestures where fingers are close. Without code changes, the only way I was able to get somewhat decent support was to increase the neutral value offset by about 60 to 70.
This in turn introduced a ton of jitter, and required the activation and deactivation thresholds to be set extremely low when using the cursor. From there, I made an implementation which would start with a high neutral, then back it off if only one touch was detected. This helped, but was still pretty inconsistent and faced the same issues as just having a high neutral offset.
I've done a fair bit of testing with the touch pad with the pixel suppression, and had multiple people trying it out on my laptop. With the attached Surface Laptop Studio 2 configuration, it seems I am able to get a pretty much identical touch pad experience to when running in Windows, with no hiccups.
Perhaps there might be a better way to do this, but this seems to have done the trick for me - figured it would be worth sharing.